/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cx1.service.impl;

import com.rits.cloning.Cloner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import net.ricecode.similarity.JaroWinklerStrategy;
import net.ricecode.similarity.SimilarityStrategy;
import net.ricecode.similarity.StringSimilarityService;
import net.ricecode.similarity.StringSimilarityServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.cx1.dao.api.IPhotoDao;
import org.cx1.dao.api.IPlaceDao;
import org.cx1.dao.impl.PhotoDao;
import org.cx1.dao.impl.PlaceDao;
import org.cx1.model.Photo;
import org.cx1.model.Place;
import org.cx1.model.ds.MockDS;
import org.cx1.model.utils.KPlaceTypeIDs;
import org.cx1.model.utils.PhotoComparator;
import org.cx1.model.utils.ServiceResponse;
import org.cx1.service.api.IPhotoService;
import org.cx1.service.api.IPlaceService;
import org.cx1.service.utils.IDGenerator;

/**
 *
 * @author ECH
 */
public class DPlaceService implements IPlaceService {

    private IPlaceDao placeDao = new PlaceDao();    
    private IPhotoDao photoDao = new PhotoDao();   
    
    private IPhotoService photoService = new DPhotoService();
    private Cloner cloner = new Cloner();
    
    @Override
    public ServiceResponse<String> create(Place place) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Place entry = new Place();
            id = place.getId();
            
            if (StringUtils.isEmpty(id)) {
                id = IDGenerator.generateID();                
            }
            entry.setId(id);            
            entry.setPlaceTypeID(place.getPlaceTypeID());
            
            entry.setTitle(place.getTitle());
            entry.setDescription(place.getDescription());
            entry.setShortDescription(place.getShortDescription());
            entry.setNotes(place.getNotes());
            
            entry.setAddress(place.getAddress());
            
            entry.setStreet(place.getStreet());
            entry.setBarangay(place.getBarangay());
            entry.setCity(place.getCity());
            entry.setRegion(place.getRegion());
            entry.setCountry(place.getCountry());
            
            entry.setZip(place.getZip());
            
            entry.setLat(place.getLat());
            entry.setLng(place.getLng());
            
            entry.setWikiURL(place.getWikiURL());
            entry.setFoursqVenueID(place.getFoursqVenueID());
            entry.setImpressions(place.getImpressions());
            entry.setViews(place.getViews());
            
            entry.setPrimaryPhotoID(place.getPrimaryPhotoID());
            entry.setPhotoIDs(place.getPhotoIDs());
                        
            entry.setCityIDs(place.getCityIDs());
            entry.setDistrictIDs(place.getDistrictIDs());
            entry.setBuildingIDs(place.getBuildingIDs());
            entry.setVillageIDs(place.getVillageIDs());
                                
            entry.setActive(true);
            entry.setDateCreated(new Date());
            entry.setDateModified(new Date());
                        
            placeDao.add(entry);
            
            if (entry.getCityIDs() != null && entry.getCityIDs().size() > 0) {
                for (String cityID : entry.getCityIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), cityID, KPlaceTypeIDs.CITY);
                }
            }
            if (entry.getDistrictIDs() != null && entry.getDistrictIDs().size() > 0) {
                for (String districtID : entry.getDistrictIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), districtID, KPlaceTypeIDs.DISTRICT);
                }
            }
            if (entry.getBuildingIDs() != null && entry.getBuildingIDs().size() > 0) {
                for (String buildingID : entry.getBuildingIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), buildingID, KPlaceTypeIDs.BUILDING);
                }
            }
            if (entry.getVillageIDs() != null && entry.getVillageIDs().size() > 0) {
                for (String villageIDs : entry.getVillageIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), villageIDs, KPlaceTypeIDs.VILLAGE);
                }
            }
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse("");
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<List<Place>> readAll(int offset, int limit) {
        ServiceResponse<List<Place>> response = new ServiceResponse<List<Place>>();
        List<Place> places = new ArrayList<Place>();
        try {            
            List<Place> records = placeDao.getAll();
            if (records != null && records.size() > 0) {
                if (offset == 0 && limit == 0) {
                    places.addAll(records);
                }
                else if (offset < records.size() && limit < records.size()) {
                    places.addAll( records.subList(offset, limit) );
                }              
            }            
            response.setResponse(places);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    @Override
    public ServiceResponse<Place> read(String id) {
        ServiceResponse<Place> response = new ServiceResponse<Place>();
        Place place = null;
        try {            
            place = placeDao.getById(id);
            populatePlaceAttributes(place);
            
            response.setResponse(place);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Place> readShallow(String id) {
        ServiceResponse<Place> response = new ServiceResponse<Place>();
        Place place = null;
        try {            
            place = placeDao.getById(id);
            
            if (place.getCities() != null) {
                place.getCities().clear();                
            }
            
            if (place.getDistricts() != null) {
                place.getDistricts().clear();                
            }
            if (place.getBuildings() != null) {
                place.getBuildings().clear();                
            }
            if (place.getVillages() != null) {
                place.getVillages().clear();                
            }
            
            if (place.getListings() != null) {
                place.getListings().clear();                
            }
            
            response.setResponse(place);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }


    @Override
    public ServiceResponse<Boolean> update(Place place) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            String targetID = place.getId(); 
            Place targetPlace = placeDao.getById(targetID);          
                        
            //CX: update dabase record
            if (targetPlace != null) {
                targetPlace.setPlaceTypeID(place.getPlaceTypeID());

                targetPlace.setTitle(place.getTitle());
                targetPlace.setNotes(place.getNotes());
                targetPlace.setDescription(place.getDescription());
                targetPlace.setShortDescription(place.getShortDescription());

                targetPlace.setAddress(place.getAddress());

                targetPlace.setNumber(place.getNumber());
                targetPlace.setStreet(place.getStreet());
                targetPlace.setBarangay(place.getBarangay());
                targetPlace.setCity(place.getCity());
                targetPlace.setRegion(place.getRegion());
                targetPlace.setCountry(place.getCountry());
                targetPlace.setZip(place.getZip());

                targetPlace.setLat(place.getLat());
                targetPlace.setLng(place.getLng());
                
                targetPlace.setWikiURL(place.getWikiURL());
                targetPlace.setFoursqVenueID(place.getFoursqVenueID());
                targetPlace.setImpressions(place.getImpressions());
                targetPlace.setViews(place.getViews());
                
                targetPlace.setCityIDs(place.getCityIDs());
                targetPlace.setDistrictIDs(place.getDistrictIDs());
                targetPlace.setBuildingIDs(place.getBuildingIDs());
                targetPlace.setVillageIDs(place.getVillageIDs());                
                    
                targetPlace.setDateModified(new Date()); 
                
                placeDao.update(targetPlace);
                
                //CX: clear places
                placeDao.deleteAllPlaceRef(targetPlace.getId());
                
                //CX: add new places
                if (targetPlace.getCityIDs() != null && targetPlace.getCityIDs().size() > 0) {
                    for (String cityID : targetPlace.getCityIDs()) {                    
                        placeDao.addPlaceRef(targetPlace.getId(), cityID, KPlaceTypeIDs.CITY);
                    }
                }
                if (targetPlace.getDistrictIDs() != null && targetPlace.getDistrictIDs().size() > 0) {
                    for (String districtID : targetPlace.getDistrictIDs()) {                    
                        placeDao.addPlaceRef(targetPlace.getId(), districtID, KPlaceTypeIDs.DISTRICT);
                    }
                }
                if (targetPlace.getBuildingIDs() != null && targetPlace.getBuildingIDs().size() > 0) {
                    for (String buildingID : targetPlace.getBuildingIDs()) {                    
                        placeDao.addPlaceRef(targetPlace.getId(), buildingID, KPlaceTypeIDs.BUILDING);
                    }
                }
                if (targetPlace.getVillageIDs() != null && targetPlace.getVillageIDs().size() > 0) {
                    for (String villageIDs : targetPlace.getVillageIDs()) {                    
                        placeDao.addPlaceRef(targetPlace.getId(), villageIDs, KPlaceTypeIDs.VILLAGE);
                    }
                }
                
                success = true;
            }   
                
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Boolean> delete(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {            
            placeDao.deleteById(id);
            success = true;        
            response.setResponse(success);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<String> readIDByTitle(String title) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = "";
        try {            
            List<Place> records = placeDao.getAll();
            if (records != null && records.size() > 0) {
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getTitle(), title)) {
                        id = record.getId();
                        break;
                    }
                }
            }            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse("");
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<List<Place>> readAllByType(String placeTypeID, int offset, int limit) {
        ServiceResponse<List<Place>> response = new ServiceResponse<List<Place>>();
        List<Place> places = new ArrayList<Place>();
        try {            
            List<Place> records = placeDao.getAll();
            List<Place> typeRecords = new ArrayList<Place>();
            
            if (records != null && records.size() > 0) {
                
                for (Place record : records) {
                    if (StringUtils.equalsIgnoreCase(record.getPlaceTypeID(), placeTypeID)) {
                        typeRecords.add(record);
                    }
                }
                
                if (typeRecords != null && typeRecords.size() > 0) {
                    if (offset == 0 && limit == 0) {
                        places.addAll(typeRecords);
                    }
                    else if (offset < typeRecords.size() && limit < typeRecords.size()) {
                        places.addAll( typeRecords.subList(offset, limit) );
                    }            
                    else {
                        places.addAll(typeRecords);
                    }                    
                }
            }            
            response.setResponse(places);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }

    @Override
    public ServiceResponse<Place> readClosestMatch(String placeTypeID, String title) {
        ServiceResponse<Place> response = new ServiceResponse<Place>();
        Place place = null;
        try {            
            List<Place> records = placeDao.getAll();
            if (records != null && records.size() > 0) {
                for (Place record : records) {
                    if (StringUtils.equals(record.getPlaceTypeID(), placeTypeID)) {
                        SimilarityStrategy strategy = new JaroWinklerStrategy();
                        StringSimilarityService service = new StringSimilarityServiceImpl(strategy);
                        double score = service.score(record.getTitle(), title);    
                        
                        if (score >= 0.9) {
                            place = record;
                            break;
                        }
                    }
                }
            }                        
            response.setResponse(place);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    
    private void populatePlaceAttributes(Place place) {
        if (place != null) {                       
            
            //CX: populate cities
            List<String> cityIDs = placeDao.getAllPlaceRefIDs(place.getId(), KPlaceTypeIDs.CITY);
            if (cityIDs != null && cityIDs.size() > 0) {
                place.setCityIDs(cityIDs);
            }
            
            if (place.getCities() == null) {
                place.setCities(new ArrayList<Place>());
            }
            place.getCities().clear();
            
            if (place.getCityIDs() != null && place.getCityIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;
                
                for (String placeID : place.getCityIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getCities().add(sr1.getResponse());
                    }
                }                    
            }                
            
            //CX: populate districts
            List<String> districtIDs = placeDao.getAllPlaceRefIDs(place.getId(), KPlaceTypeIDs.DISTRICT);
            if (districtIDs != null && districtIDs.size() > 0) {
                place.setDistrictIDs(districtIDs);
            }
            
            if (place.getDistricts() == null) {
                place.setDistricts(new ArrayList<Place>());
            }
            place.getDistricts().clear();
            
            if (place.getDistrictIDs()!= null && place.getDistrictIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getDistrictIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getDistricts().add(sr1.getResponse());
                    }
                }                    
            }          
            
            //CX: populate buildings
            List<String> buildingIDs = placeDao.getAllPlaceRefIDs(place.getId(), KPlaceTypeIDs.BUILDING);
            if (buildingIDs != null && buildingIDs.size() > 0) {
                place.setBuildingIDs(buildingIDs);
            }
                        
            if (place.getBuildings() == null) {
                place.setBuildings(new ArrayList<Place>());
            }
            place.getBuildings().clear();
            
            if (place.getBuildingIDs()!= null && place.getBuildingIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getBuildingIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getBuildings().add(sr1.getResponse());
                    }
                }                    
            }        
            
            //CX: populate villages
            List<String> villageIDs = placeDao.getAllPlaceRefIDs(place.getId(), KPlaceTypeIDs.VILLAGE);
            if (villageIDs != null && villageIDs.size() > 0) {
                place.setVillageIDs(villageIDs);
            }
            
            if (place.getVillages() == null) {
                place.setVillages(new ArrayList<Place>());
            }
            place.getVillages().clear();
            
            if (place.getVillageIDs()!= null && place.getVillageIDs().size() > 0) {
                ServiceResponse<Place> sr1 = null;

                for (String placeID : place.getVillageIDs()) {
                    sr1 = this.readShallow(placeID);

                    if (sr1.isSuccessful() && sr1.getResponse() != null) {
                        place.getVillages().add(sr1.getResponse());
                    }
                }                    
            }        
            
            //CX: populate attributes
            place.setDisplayCity(buildDisplayCity(place));           
                        
            //CX: populate photoIDs
            place.setPhotoIDs(photoDao.getPlacePhotoIds(place.getId()));
                        
            //CX: populate photos
            place.getPhotos().clear();                
            if (place.getPhotoIDs() != null && place.getPhotoIDs().size() > 0) {
                ServiceResponse<Photo> sr2 = null;

                for (String photoID : place.getPhotoIDs()) {
                    sr2 = this.photoService.read(photoID);                        
                    if (sr2.isSuccessful() && sr2.getResponse() != null) {
                        place.getPhotos().add(sr2.getResponse());
                    }
                }      
                Collections.sort(place.getPhotos(), new PhotoComparator());              
            }
            
            //CX: populate primary            
            if (place.getPhotos() != null && place.getPhotos().size() > 0) {
                place.setPrimaryPhoto(place.getPhotos().get(0));
            }
        }            
    }
    
    private String buildDisplayCity(Place place) {
        String displayCity = "";    
        try {
            if (!StringUtils.isEmpty(place.getCity())) {
                displayCity = place.getCity();
                displayCity = displayCity.replaceAll("city", "");
                displayCity = displayCity.replaceAll("City", "");
                displayCity = displayCity.trim();
            }             
        } catch (Exception ex) {
            
        }   
        return displayCity;
    }
    
    private Place clonePlace(Place place) {
        return cloner.deepClone(place);
    }
    
    
    public ServiceResponse<String> createImport(Place place) {
        ServiceResponse<String> response = new ServiceResponse<String>();
        String id = null;        
        try {            
            Place entry = new Place();
            id = place.getId();
            
            entry.setId(id);            
            entry.setPlaceTypeID(place.getPlaceTypeID());
            
            entry.setTitle(place.getTitle());
            entry.setDescription(place.getDescription());
            entry.setShortDescription(place.getShortDescription());
            entry.setNotes(place.getNotes());
            
            entry.setAddress(place.getAddress());
            
            entry.setStreet(place.getStreet());
            entry.setBarangay(place.getBarangay());
            entry.setCity(place.getCity());
            entry.setRegion(place.getRegion());
            entry.setCountry(place.getCountry());
            
            entry.setZip(place.getZip());
            
            entry.setLat(place.getLat());
            entry.setLng(place.getLng());
            
            entry.setWikiURL(place.getWikiURL());
            
            entry.setPrimaryPhotoID(place.getPrimaryPhotoID());
            entry.setPhotoIDs(place.getPhotoIDs());
                        
            entry.setCityIDs(place.getCityIDs());
            entry.setDistrictIDs(place.getDistrictIDs());
            entry.setBuildingIDs(place.getBuildingIDs());
            entry.setVillageIDs(place.getVillageIDs());
                    
            entry.setActive(place.isActive());
            entry.setDateCreated(place.getDateCreated());
            entry.setDateModified(place.getDateModified());
                        
            placeDao.add(entry);
            
            if (entry.getCityIDs() != null && entry.getCityIDs().size() > 0) {
                for (String cityID : entry.getCityIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), cityID, KPlaceTypeIDs.CITY);
                }
            }
            if (entry.getDistrictIDs() != null && entry.getDistrictIDs().size() > 0) {
                for (String districtID : entry.getDistrictIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), districtID, KPlaceTypeIDs.DISTRICT);
                }
            }
            if (entry.getBuildingIDs() != null && entry.getBuildingIDs().size() > 0) {
                for (String buildingID : entry.getBuildingIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), buildingID, KPlaceTypeIDs.BUILDING);
                }
            }
            if (entry.getVillageIDs() != null && entry.getVillageIDs().size() > 0) {
                for (String villageIDs : entry.getVillageIDs()) {                    
                    placeDao.addPlaceRef(entry.getId(), villageIDs, KPlaceTypeIDs.VILLAGE);
                }
            }
            
            response.setResponse(id);
            response.setSuccessful(true);            
        } 
        catch (Exception ex) {
            response.setResponse("");
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response; 
    }
    
    
    public static void main(String[] argv) {
        
        IPlaceService placeService = new DPlaceService();  
        
        /*
        for (int i = 1; i < 11; i++) {
            Place place = new Place();
            place.setId(IDGenerator.generateID());
            place.setTitle("Place " + i);
            placeService.create(place);
        }
        */
        
        /*
        ServiceResponse<List<Place>> response1 = placeService.readAll(0, 0);
        List<Place> places = response1.getResponse();
        if (places != null && places.size() > 0) {
            for (Place place : places) {
                System.out.println("CX: " + place.getTitle() + " - " + place.getId());
            }
        }
        */
        
        /*
        ServiceResponse<Place> response1 = placeService.read("f202627093");
        Place place = response1.getResponse();
        if (place != null) {
            System.out.println("CX: " + place.getId());
            System.out.println("CX: " + place.getTitle());
        }
        */        
        
        /*
        ServiceResponse<Place> response1 = placeService.read("f202627093");
        Place place = response1.getResponse();
        if (place != null) {
            place.setTitle("Place TWO");
            placeService.update(place);
            
            ServiceResponse<Place> response2 = placeService.read("f202627093");
            Place place2 = response2.getResponse();
            if (place2 != null) {
                System.out.println("CX: " + place2.getTitle());
                System.out.println("CX: " + place2.getId());
            }
        }        
        */
        
        /*
        ServiceResponse<Boolean> response1 = placeService.delete("1a2136ac2");           
        ServiceResponse<Place> response2 = placeService.read("1a2136ac2");        
        Place place2 = response2.getResponse();
        if (place2 == null) {
            System.out.println("YAY");
        } 
        */
    }

    
    @Override
    public ServiceResponse<Boolean> incrementImpressions(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {             
            //CX: increment impression by 1
            this.placeDao.incrementImpressions(id);
            
            //Listing record = this.read(id).getResponse();
            //if (record != null) {
                //long impressions = record.getImpressions();
                //record.setImpressions(  impressions += 1 );
                //this.update(record);
            //}
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);            
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }

    @Override
    public ServiceResponse<Boolean> incrementViews(String id) {
        ServiceResponse<Boolean> response = new ServiceResponse<Boolean>();
        boolean success = false;
        try {                         
            //CX: increment views by 1
            this.placeDao.incrementViews(id);
            
            //Listing record = this.read(id).getResponse();
            //if (record != null) {
                //long views = record.getViews();
                //record.setViews( views += 1 );                    
                //this.update(record);
            //}
            success = true;
            response.setResponse(success);
            response.setSuccessful(success);                       
        } 
        catch (Exception ex) {
            response.setResponse(null);
            response.setSuccessful(false);
            response.setMessage(ex.getMessage());
            response.setException(ex);
            ex.printStackTrace();            
        }
        return response;
    }
    
}
